package com.taoz.rpc.core.server.tcp;

import com.taoz.rpc.core.model.RpcRequest;
import com.taoz.rpc.core.model.RpcResponse;
import com.taoz.rpc.core.registry.LocalRegistry;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;
import io.vertx.core.parsetools.RecordParser;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

@Slf4j
public class VertxTcpRequestHandler implements Handler<NetSocket> {
    @Override
    public void handle(NetSocket socket) {
        RecordParser parser = RecordParser.newFixed(8);
        parser.setOutput(new Handler<Buffer>() {
            int bodySize = -1;
            Buffer resultBuffer = Buffer.buffer();
            @Override
            public void handle(Buffer buffer) {
                resultBuffer.appendBuffer(buffer);
                if (bodySize == -1) {
                    bodySize = buffer.getInt(4);
                    parser.fixedSizeMode(bodySize);
                } else {
                    ProtocolMessage<?> message = ProtocolMessage.toMessage(resultBuffer);
                    RpcRequest rpcRequest = (RpcRequest) message.getBody();
                    RpcResponse rpcResponse = new RpcResponse();
                    try {
                        Class<?> clazz = LocalRegistry.get(rpcRequest.getServiceName());
                        Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
                        Object result = method.invoke(clazz.newInstance(), rpcRequest.getArgs());
                        rpcResponse.setData(result);
                        rpcResponse.setMessage("ok");
                        rpcResponse.setDataType(method.getReturnType());
                    } catch (Exception e) {
                        rpcResponse.setMessage(e.getMessage());
                    }
                    ProtocolMessage.Header header = message.getHeader();
                    header.setType(ProtocolType.RESPONSE);
                    ProtocolMessage<RpcResponse> returnMessage = new ProtocolMessage<>(header, rpcResponse);
                    Buffer returnBuffer = ProtocolMessage.toBuffer(returnMessage);
                    socket.write(returnBuffer);
                    bodySize = -1;
                    resultBuffer = Buffer.buffer();
                }
            }
        });
        socket.handler(parser);
    }
}
